Kubernetes Components
A Kubernetes cluster consists of a control plane and one or more worker nodes. The control plane manages overall cluster state; nodes run the actual workloads.
Think of the control plane as the brain (makes decisions) and nodes as the muscles (do the work).
Control Plane Components
The control plane manages the overall state of the cluster — making global decisions (like scheduling) and detecting/responding to cluster events.
| Component | Role | Key fact |
|---|---|---|
| kube-apiserver | Exposes the Kubernetes HTTP API | Front-end for the control plane; all kubectl commands go here first |
| etcd | Persistent key-value store | Stores ALL cluster data; consistent & highly-available |
| kube-scheduler | Assigns Pods to nodes | Watches for new Pods with no assigned node |
| kube-controller-manager | Runs controller loops | Implements K8s API behavior (Node, Job, EndpointSlice controllers…) |
| cloud-controller-manager | Integrates with cloud providers | Optional — only in cloud deployments |
kube-apiserver
The core component that exposes the Kubernetes HTTP API. It's the single entry point for all cluster operations. Designed to scale horizontally — you can run multiple instances.
etcd
A consistent, highly-available key-value store used as Kubernetes' backing store for all cluster data. If you run Kubernetes in production, always have a backup plan for etcd.
kube-scheduler
Watches for newly created Pods that have no assigned node and selects a node for them to run on. Factors considered include: resource requirements, hardware/software/policy constraints, affinity/anti-affinity rules, data locality, and deadlines.
kube-controller-manager
Runs controller processes. Each controller is a separate control loop, but compiled into one binary for simplicity. Examples:
- Node controller — notices when nodes go down
- Job controller — watches Job objects, creates Pods
- EndpointSlice controller — links Services to Pods
- ServiceAccount controller — manages default accounts
cloud-controller-manager (optional)
Embeds cloud-specific control logic. Lets you link your cluster to your cloud provider's API. Only runs if you're using a cloud provider. Includes:
- Node controller — checking cloud provider for node deletion
- Route controller — setting up cloud network routes
- Service controller — managing cloud load balancers
APIserver → etcd → Scheduler → Controller = AESC — "Always Ensuring Stable Clusters"
Which control plane component is responsible for assigning unscheduled Pods to nodes?
nodeName: "" and assigns them to a suitable node based on resource availability, constraints, and policies.
Node Components
Node components run on every worker node, maintaining running Pods and providing the Kubernetes runtime environment.
| Component | Role | Key fact |
|---|---|---|
| kubelet | Node agent | Ensures containers in Pods are running & healthy. Does NOT manage containers not created by K8s. |
| kube-proxy | Network proxy | Implements the Service concept by maintaining network rules. Uses OS packet filtering if available. |
| Container runtime | Runs containers | Any CRI-compliant runtime: containerd, CRI-O, etc. |
kubelet
An agent that runs on each node. Takes a set of PodSpecs (provided via various mechanisms) and ensures the containers described are running and healthy.
The kubelet only manages containers created through Kubernetes. It does not manage containers you start manually on the node.
kube-proxy
A network proxy that runs on each node, implementing part of the Kubernetes Service concept. Maintains network rules that allow network communication to Pods from inside or outside the cluster.
Uses the OS packet filtering layer (e.g., iptables or ipvs) when available; otherwise forwards traffic itself.
Container Runtime
The fundamental component that empowers Kubernetes to run containers. Kubernetes supports any runtime implementing the Kubernetes CRI (Container Runtime Interface).
A developer manually starts a container on a worker node using docker run (bypassing Kubernetes). Will kubelet manage this container?
Architecture at a Glance
Every request flows: kubectl → kube-apiserver → etcd (persist). Then controllers react, scheduler assigns, kubelet starts containers.
| Layer | Components | Lives on |
|---|---|---|
| Control Plane | apiserver, etcd, scheduler, controller-manager, (cloud-controller-manager) | Dedicated control node(s) |
| Worker Node | kubelet, kube-proxy, container runtime | Every worker node |
| Optional Add-ons | DNS, Dashboard, networking plugins, storage plugins | Cluster-wide |
Key Relationships
- apiserver ↔ etcd: The apiserver is the only component that writes to etcd
- scheduler → apiserver: Scheduler watches the apiserver for unbound Pods
- controller-manager → apiserver: Controllers use the apiserver to observe and act
- kubelet → apiserver: Each kubelet registers with and reports to the apiserver
- kube-proxy → apiserver: kube-proxy watches Services and Endpoints via the apiserver
Which is the ONLY component that directly reads/writes to etcd?
Objects in Kubernetes
Kubernetes objects are persistent entities in the Kubernetes system. Kubernetes uses them to represent the state of your cluster. Specifically, they can describe:
- What containerized applications are running (and on which nodes)
- The resources available to those applications
- The policies around how those applications behave — restart policies, upgrades, fault-tolerance
A Kubernetes object is a "record of intent" — once you create the object, Kubernetes will constantly work to ensure that the object exists. By creating an object, you're telling Kubernetes the desired state you want.
To work with Kubernetes objects — create, modify, or delete — you use the Kubernetes API. The kubectl CLI makes the necessary API calls for you. You can also use the API directly via Client Libraries.
Object Spec and Status
Almost every Kubernetes object includes two nested object fields that govern the object's configuration:
| Field | What it is | Who sets it |
|---|---|---|
| spec | Desired state — the characteristics you want the resource to have | You (the user), when you create/update the object |
| status | Current state — describes the actual state of the object | Kubernetes system (supplied and updated continuously) |
You create a Deployment with spec.replicas: 3 — Kubernetes starts 3 Pods and updates status to reflect this. If one Pod fails (status changes), Kubernetes reconciles by starting a replacement to match spec.
The Kubernetes control plane continually and actively manages every object's actual state to match the desired state you supplied.
You have a Deployment with spec.replicas: 3. One Pod crashes. What does Kubernetes do?
Describing a Kubernetes Object (Manifests)
When you create an object, you provide a manifest — a file (typically YAML) that includes the object spec describing its desired state, plus basic identification. Kubernetes manifests are YAML by convention (JSON also supported).
The 4 Required Fields
| Field | Purpose | Example |
|---|---|---|
| apiVersion | Which version of the Kubernetes API you're using to create this object | apps/v1, v1 |
| kind | What kind of object you want to create | Deployment, Pod, Service |
| metadata | Data that helps uniquely identify the object — name, UID, optional namespace | name: nginx-deployment |
| spec | What state you desire for the object (format varies per object type) | replicas: 2 |
Example Deployment Manifest
Applying a Manifest
Server-Side Field Validation
Starting with Kubernetes v1.25, the API server offers server-side field validation that detects unrecognized or duplicate fields in an object. It provides all the functionality of kubectl --validate on the server side.
Which field in a Kubernetes manifest specifies the desired state of the object?
metadata identifies it, kind names the object type, apiVersion specifies the API version.
Kubernetes Object Management
The kubectl tool supports three different ways to create and manage objects. Warning: use only one technique per object — mixing techniques causes undefined behavior.
| Technique | Operates on | Recommended env | Writers | Learning curve |
|---|---|---|---|---|
| Imperative commands | Live objects | Development | 1+ | Lowest |
| Imperative object config | Individual files | Production | 1 | Moderate |
| Declarative object config | Directories of files | Production | 1+ | Highest |
A Kubernetes object should be managed using only one technique. Mixing and matching techniques for the same object results in undefined behavior.
Imperative Commands & Configuration
Imperative Commands
The user operates directly on live objects in a cluster. Operations are provided to kubectl as arguments or flags. Recommended for getting started or running one-off tasks — provides no history of previous configurations.
Imperative Object Configuration
The kubectl command specifies the operation (create, replace, etc.) plus at least one file name. The file must contain a full definition of the object in YAML or JSON format.
The replace command replaces the existing spec with the newly provided one, dropping all changes missing from the file. Do not use with resource types whose specs are updated independently (e.g., LoadBalancer Services have their externalIPs updated by the cluster).
Declarative Object Configuration
The user operates on object configuration files stored locally but does NOT define the operations to be taken. Create, update, and delete operations are automatically detected per-object by kubectl. Enables working on directories where different operations might be needed for different objects.
Declarative config uses the patch API operation to write only observed differences — instead of replacing the entire object. This means changes made by other writers (e.g. autoscalers) are retained even if not in the config file.
Comparison Summary
| Concern | Imperative cmd | Imp. config | Declarative |
|---|---|---|---|
| Source control | ✗ | ✓ | ✓ |
| Audit trail | ✗ | ✓ | ✓ |
| Retains live changes | N/A | ✗ | ✓ |
| Works on directories | ✗ | ✗ | ✓ |
| Learning curve | Lowest | Moderate | Highest |
| Debug complexity | Low | Low | High |
You're running a LoadBalancer Service. Its externalIPs field is automatically updated by the cluster. Which command should you AVOID when updating this Service?
kubectl replace replaces the entire spec with what's in the file, dropping the cluster-managed externalIPs field. Use kubectl apply (patch-based) or kubectl patch for targeted updates instead.
Object Names and IDs
Each object in your cluster has a Name that is unique for that type of resource. Every Kubernetes object also has a UID that is unique across your whole cluster.
For non-unique user-provided attributes, Kubernetes provides labels and annotations.
Name — unique per resource type within a namespace (client-provided, reusable after deletion). UID — globally unique across the entire cluster lifetime (system-generated, never reused).
Names
A Name is a client-provided string that refers to an object in a resource URL — e.g., /api/v1/pods/some-name.
- Only one object of a given kind can have a given name at a time
- If you delete an object, you can create a new one with the same name
- Names must be unique across all API versions of the same resource (API version is irrelevant for uniqueness — it's API group + resource type + namespace + name)
If a Node representing a physical host is re-created under the same name without deleting the old Node object, Kubernetes treats the new host as the old one — this can cause inconsistencies.
generateName
When generateName is provided instead of name, the server uses the value as a name prefix and appends a generated suffix. Since Kubernetes v1.31, the server makes up to 8 attempts to generate a unique name before returning an HTTP 409 response.
Four Name Constraint Types
| Constraint type | Max length | Characters allowed | Start/End |
|---|---|---|---|
| DNS Subdomain | 253 chars | lowercase alphanumeric, -, . |
alphanumeric |
| RFC 1123 Label | 63 chars | lowercase alphanumeric, - |
alphanumeric |
| RFC 1035 Label | 63 chars | lowercase alphanumeric, - |
must start with alphabetic character |
| Path Segment | varies | cannot be . or .., cannot contain / or % |
— |
DNS Subdomain Names (most common)
Required by most resource types (Deployments, ConfigMaps, etc.). Must:
- Contain no more than 253 characters
- Contain only lowercase alphanumeric characters,
-, or. - Start and end with an alphanumeric character
RFC 1123 Label Names
Used by some resource types. Must:
- Contain at most 63 characters
- Contain only lowercase alphanumeric characters or
- - Start and end with an alphanumeric character
When RelaxedServiceNameValidation feature gate is enabled, Service object names are allowed to start with a digit.
RFC 1035 Label Names
Same as RFC 1123 but must start with an alphabetic character (not a digit). Used by some specific resource types.
Path Segment Names
Some resource types require names to be safely encodable as a path segment. The name:
- May not be
.or.. - May not contain
/or%
UIDs
A Kubernetes UID is a system-generated string that uniquely identifies objects. Every object created over the whole lifetime of a cluster has a distinct UID — intended to distinguish between historical occurrences of similar entities.
- UIDs are universally unique identifiers (UUIDs)
- Standardized as ISO/IEC 9834-8 and ITU-T X.667
- System-generated — not set by users
- Never reused, even if an object with the same name is recreated
Think of Name like a username (unique now, can be reused after account deletion) and UID like a social security number (unique forever, never reassigned).
You delete a Pod named my-pod and create a new Pod with the same name. The new Pod will have:
A ConfigMap name must conform to DNS subdomain rules. Which of these names is INVALID?
Labels
Labels are key/value pairs attached to objects such as Pods. They specify identifying attributes that are meaningful and relevant to users, but do not directly imply semantics to the core system.
Labels can be used to organize and to select subsets of objects. Labels can be attached at creation time and modified at any time. Each object can have a set of key/value labels; each key must be unique per object.
Labels are for identifying attributes used in queries and selection. Non-identifying information (build metadata, tool info, etc.) should use annotations instead.
Motivation
Labels enable users to map their own organizational structures onto system objects in a loosely coupled fashion, without requiring clients to store those mappings.
Service deployments and batch processing pipelines are often multi-dimensional entities — multiple partitions or deployments, release tracks, tiers, micro-services. Management often requires cross-cutting operations, which breaks encapsulation of strictly hierarchical representations.
Common label examples
Syntax and character set
Label keys have two segments: an optional prefix and a name, separated by a slash (/).
| Segment | Rules |
|---|---|
| Name (required) | ≤63 characters; start and end with alphanumeric [a-z0-9A-Z]; may contain dashes, underscores, dots between |
| Prefix (optional) | DNS subdomain ≤253 chars, followed by /. If omitted, key is private to the user |
Automated system components (kube-scheduler, kube-controller-manager, kube-apiserver, kubectl, or third-party automation) that add labels to end-user objects must specify a prefix. The kubernetes.io/ and k8s.io/ prefixes are reserved for Kubernetes core components.
Valid label values
- Must be 63 characters or less (can be empty)
- Unless empty, must begin and end with an alphanumeric character
[a-z0-9A-Z] - Could contain dashes (
-), underscores (_), dots (.), and alphanumerics between
Example manifest with labels
Which label key is VALID according to Kubernetes label syntax rules?
app.kubernetes.io is a DNS subdomain) + valid name (version). The first has two slashes (invalid). MY_LABEL has uppercase (invalid for the name segment if mixing — actually uppercase IS allowed in names). -starts-with-dash starts with a dash (must start with alphanumeric).
Label Selectors
Unlike names and UIDs, labels do not provide uniqueness — we expect many objects to carry the same labels. Via a label selector, the client can identify a set of objects. The label selector is the core grouping primitive in Kubernetes.
The API supports two types of selectors: equality-based and set-based. A selector can be made of multiple requirements, comma-separated. All requirements must be satisfied — the comma acts as a logical AND (&&) operator.
For both equality-based and set-based conditions, there is no logical OR (||) operator. Ensure your filter statements are structured accordingly.
For some API types such as ReplicaSets, the label selectors of two instances must not overlap within a namespace — the controller would see conflicting instructions and fail to determine how many replicas should be present.
Equality-based requirements
Allow filtering by label keys and values. Three operators: =, == (synonyms for equality) and != (inequality).
The != operator also selects resources with no labels with the given key at all. One usage scenario: node selection criteria. Example selects nodes where accelerator=nvidia-tesla-p100:
Equality-based = simple key/value match with =, ==, !=.
Set-based = match against a set of values with in, notin, exists.
Comma always means AND — there is no OR.
What does the selector environment=production,tier!=frontend match?
!= operator also matches objects that have no "tier" label at all — not just those with tier≠frontend.
Set-based Selectors
Set-based label requirements allow filtering keys according to a set of values. Three operators are supported: in, notin, and exists (key identifier only).
| Expression | Meaning |
|---|---|
environment in (production, qa) | key=environment, value is production or qa |
tier notin (frontend, backend) | value is NOT frontend or backend, OR key is absent |
partition | key=partition exists; no value restriction |
!partition | key=partition must NOT exist; no value check |
Set-based is a superset of equality-based. For example, environment=production is equivalent to environment in (production). Similarly, != is equivalent to notin. Set-based requirements can be mixed with equality-based in the same selector.
Mixing selector types
Set-based and equality-based requirements can be combined. Example — objects in partition customerA or customerB, but not in environment=qa:
The comma separator acts as a logical AND operator — all requirements must be satisfied simultaneously.
Use set-based when you need: an OR on values (in), checking key existence without caring about value (exists), or excluding multiple values at once (notin). Equality-based only handles single-value comparisons.
The selector tier notin (frontend, backend) will match which Pods?
!= in equality-based selectors.
What does the selector partition (alone, without a value) do?
partition) uses the exists operator — it selects all resources that have that label key, regardless of value. !partition inverts this, selecting resources that do NOT have the key.
API LIST and WATCH Filtering
For list and watch operations, you can specify label selectors to filter the sets of objects returned. The filter is passed as a query parameter in the URL.
| Selector type | Query param format |
|---|---|
| Equality-based | ?labelSelector=environment%3Dproduction,tier%3Dfrontend |
| Set-based | ?labelSelector=environment+in+%28production%2Cqa%29%2Ctier+in+%28frontend%29 |
kubectl examples
Both selector styles work with kubectl get pods -l:
Set-based requirements are more expressive — they can implement the OR operator on values. For example environment in (production, qa) selects Pods in either environment — impossible with equality-based alone.
Which kubectl command selects Pods in EITHER production OR qa environment?
in operator handles OR on values. Writing two equality requirements with the same key would be contradictory (a key can't equal both at once). The || syntax doesn't exist in Kubernetes selectors.
Set References in API Objects
Some Kubernetes objects use label selectors to specify sets of other resources. Two important object types — Service and ReplicationController — use selectors to target Pods.
Service and ReplicationController
The set of Pods that a Service targets is defined by a label selector. Similarly, the ReplicationController uses a label selector to manage its Pods. Both define selectors in JSON/YAML using equality-based requirements only:
This selector is equivalent to component=redis or component in (redis).
Label selectors for Service and ReplicationController are defined in JSON/YAML as simple maps — they only support equality-based requirements. To use set-based selectors, you need newer resource types.
matchLabels & matchExpressions
Newer resources — Job, Deployment, ReplicaSet, and DaemonSet — support set-based requirements via two fields: matchLabels and matchExpressions.
| Field | Type | Description |
|---|---|---|
matchLabels |
map of {key,value} | Each pair is equivalent to an equality requirement (key=value). Equivalent to an element in matchExpressions with operator In and single value. |
matchExpressions |
list of requirements | Each requirement has a key, an operator, and a values array. Valid operators: In, NotIn, Exists, DoesNotExist. |
The values set must be non-empty for In and NotIn operators. All requirements from both matchLabels and matchExpressions are ANDed together — all must be satisfied for a match.
Selecting sets of nodes
One use case for selecting over labels is to constrain which nodes a Pod can schedule onto. This is done using node selection — see the node selection documentation for more information. The same label selector primitives apply for targeting node labels.
Service & ReplicationController → equality-based only (JSON map).
Job, Deployment, ReplicaSet, DaemonSet → set-based via matchLabels + matchExpressions.
Both matchLabels and matchExpressions must ALL match (AND logic).
In a ReplicaSet selector, matchLabels: {component: redis} is equivalent to which matchExpressions entry?
matchLabels pair {key: value} is equivalent to a matchExpressions element with operator: In and values: [value]. The In operator with a single value behaves exactly like equality.
You need a selector that targets Pods with tier in (cache, memory). Which resource type(s) support this?
in require newer resource types that support matchExpressions.
Using Labels Effectively
You can apply a single label to any resource, but this is not always the best practice. There are many scenarios where multiple labels should be used to distinguish resource sets from one another.
app — included for convenience in manual queries and simple CLI usage.
app.kubernetes.io/name — follows the recommended Kubernetes labeling conventions and is better suited for tooling and automation.
Guestbook multi-tier example
A multi-tier application (like a guestbook) needs to distinguish frontend from backend, and different roles within backend. Using multiple labels enables slicing along any dimension:
Slicing and dicing by any dimension
With multiple labels you can query across any dimension independently — without reorganizing resources:
| NAME | APP | TIER | ROLE |
|---|---|---|---|
| guestbook-fe-4n1pb | guestbook | frontend | <none> |
| guestbook-redis-master | guestbook | backend | master |
| guestbook-redis-replica | guestbook | backend | replica |
| my-nginx-divi2 | nginx | <none> | <none> |
Think of labels as dimensions on a data cube. Each label key is a dimension (app, tier, role, environment). You can query any slice — frontend only, all backends, only replicas — without restructuring the cluster.
In the guestbook example, how do you select ONLY the Redis replica Pods?
-lapp=guestbook,role=replica uses -l (filter) with AND logic. -ltier=backend would also return the master. -L is for displaying label values as columns, not filtering.
For a label used by automation tools and CI/CD pipelines, which key format is recommended?
app.kubernetes.io/name follows the recommended Kubernetes labeling conventions and is better suited for tooling and automation. The plain app key is for convenience in manual CLI queries.
Updating Labels
Sometimes you may want to relabel existing Pods and other resources before creating new ones. This can be done with kubectl label.
This first filters all Pods with app=nginx, then applies the label tier=fe to each of them.
Displaying label columns (-L)
Use -L (or --label-columns) to display label values as columns in the output:
| Flag | Purpose | Example |
|---|---|---|
-l | Filter/select resources by label (lowercase L) | -l app=nginx |
-L | Display label value as output column (uppercase L) | -L tier |
-l (lowercase) = label selector — filters which resources are shown.
-L (uppercase) = label column — adds a column showing the value of that label.
They can be combined: kubectl get pods -l app=nginx -L tier
What does kubectl label pods -l app=nginx tier=fe do?
kubectl label modifies labels on existing resources. The -l app=nginx selector identifies which Pods to update, and tier=fe is the new label to add or overwrite on each.
Namespaces
In Kubernetes, namespaces provide a mechanism for isolating groups of resources within a single cluster. Names of resources need to be unique within a namespace, but not across namespaces.
Namespace-based scoping applies only to namespaced objects (e.g. Deployments, Services). It does not apply to cluster-wide objects (e.g. StorageClass, Nodes, PersistentVolumes).
When to Use Multiple Namespaces
Namespaces are intended for use in environments with many users spread across multiple teams, or projects. For clusters with a few to tens of users, you should not need to create or think about namespaces at all.
| Use namespaces when… | Don't use namespaces when… |
|---|---|
| Many users / teams sharing a cluster | Small team, few resources |
| You need to divide cluster resources via resource quota | Distinguishing slightly different versions of the same software — use labels instead |
| You want name isolation across projects | Nesting is needed (namespaces cannot be nested) |
It is not necessary to use multiple namespaces to separate slightly different resources, such as different versions of the same software. Use labels to distinguish resources within the same namespace.
For a production cluster, consider not using the default namespace. Instead, make other namespaces and use those.
You have two versions of the same app (v1 and v2) running in the same cluster. Should you use separate namespaces?
Initial Namespaces
Kubernetes starts with four initial namespaces:
| Namespace | Purpose |
|---|---|
default | Start using the cluster without first creating a namespace. Not recommended for production. |
kube-node-lease | Holds Lease objects associated with each node. Node leases allow kubelet to send heartbeats so the control plane can detect node failure. |
kube-public | Readable by all clients (including unauthenticated). Reserved for cluster usage — resources visible/readable publicly throughout the whole cluster. Public aspect is only a convention, not a requirement. |
kube-system | Namespace for objects created by the Kubernetes system itself. |
Avoid creating namespaces with the prefix kube- — it is reserved for Kubernetes system namespaces.
Which namespace holds the Lease objects used for node heartbeats?
kube-node-lease holds Lease objects for each node. These allow kubelet to send heartbeats to the control plane — enabling node failure detection.
Working with Namespaces
Viewing namespaces
Setting namespace for a request
Use the --namespace flag to target a specific namespace for a single request:
Setting the namespace preference
You can permanently save the namespace for all subsequent kubectl commands in a context:
--namespace (or -n) — targets one namespace for a single command.
kubectl config set-context --current --namespace=... — permanently changes the default namespace for all subsequent commands in the current context.
Which command permanently sets the default namespace for all subsequent kubectl commands?
kubectl config set-context --current --namespace=<ns> permanently updates the kubeconfig context to use that namespace by default. The --namespace flag only applies to a single command.
Namespaces and DNS
When you create a Service, it creates a corresponding DNS entry of the form:
If a container only uses <service-name> (short name), it will resolve to the service local to its namespace. This is useful for using the same configuration across multiple namespaces such as Development, Staging, and Production.
To reach a service across namespaces, you must use the fully qualified domain name (FQDN).
Creating namespaces with the same name as public top-level domains can cause Services to have DNS names that overlap with public DNS records. Workloads performing DNS lookups without a trailing dot will be redirected to those services, taking precedence over public DNS. Limit namespace creation privileges to trusted users.
Namespace names must be valid RFC 1123 DNS labels — this is because they appear directly in DNS entries for Services.
A Pod in namespace "staging" uses the short name "my-svc" to call a service. Which service will it reach?
Namespace Scope & Automatic Labelling
Not all objects are in a namespace
Most Kubernetes resources (Pods, Services, Deployments, ReplicationControllers, etc.) are namespaced. However, some low-level / cluster-wide resources are not:
| Namespaced resources | Cluster-wide resources (not namespaced) |
|---|---|
| Pods, Services, Deployments | Nodes |
| ReplicationControllers, ReplicaSets | PersistentVolumes |
| ConfigMaps, Secrets | StorageClass |
| Namespace objects themselves are NOT in a namespace | ClusterRoles, ClusterRoleBindings |
Automatic labelling
Since Kubernetes 1.22 (stable), the control plane sets an immutable label kubernetes.io/metadata.name on all namespaces. The value of the label is the namespace name.
Namespaced: workload objects (Pods, Deployments, Services) — things that run or route.
Cluster-wide: infrastructure objects (Nodes, PersistentVolumes, StorageClass) — things that exist at the physical/cluster level.
Namespace objects themselves are also cluster-wide (they cannot be inside themselves).
Which of these resources is NOT namespaced (cluster-wide)?
What label does Kubernetes automatically set on all namespaces since v1.22?
kubernetes.io/metadata.name is set immutably on all namespaces by the control plane since Kubernetes 1.22 (stable). Its value is the namespace name itself.
Annotations
You can use Kubernetes annotations to attach arbitrary non-identifying metadata to objects. Clients such as tools and libraries can retrieve this metadata.
Labels — used to select objects and find collections that satisfy certain conditions.
Annotations — NOT used to identify and select objects. They store arbitrary metadata that is too large, structured, or non-identifying for labels.
Annotations, like labels, are key/value maps:
The keys and values in the annotation map must be strings. You cannot use numeric, boolean, list, or other types for either the keys or the values.
Annotation Use Cases & Syntax
What to store in annotations
| Category | Examples |
|---|---|
| Declarative config fields | Fields managed by a config layer; distinguishes them from client defaults or auto-generated fields |
| Build / release info | Timestamps, release IDs, git branch, PR numbers, image hashes, registry address |
| Observability pointers | Pointers to logging, monitoring, analytics, or audit repositories |
| Debug info | Client library or tool info: name, version, build information |
| Provenance | URLs of related objects from other ecosystem components |
| Rollout metadata | Lightweight rollout tool metadata: config or checkpoints |
| Contact info | Phone/pager numbers for persons responsible, or directory entries |
| User directives | Directives from the end-user to implementations to modify behavior or engage non-standard features |
Instead of annotations, you could store this information in an external database or directory — but that would make it much harder to produce shared client libraries and tools for deployment, management, introspection, and the like. Keeping metadata on the object keeps it co-located with the resource.
Annotation key syntax
Annotation keys have two segments: an optional prefix and a name, separated by /. Same rules as label keys:
| Segment | Rules |
|---|---|
| Name (required) | ≤63 chars; start/end with [a-z0-9A-Z]; dashes, underscores, dots between |
| Prefix (optional) | DNS subdomain ≤253 chars followed by /. If omitted, key is private to user. |
The kubernetes.io/ and k8s.io/ prefixes are reserved for Kubernetes core components. Automated system components that add annotations to end-user objects must specify a prefix.
Example manifest with annotation
You want to store the git commit hash that produced a Pod's image. Should you use a label or an annotation?
Which of these annotation values is INVALID?
true is invalid. However "true" (a string) is valid. Numbers, lists, and booleans cannot be used as annotation values.
Field Selectors
Field selectors let you select Kubernetes objects based on the value of one or more resource fields — not labels, but actual field values in the object's spec or status.
Field selectors are essentially resource filters. By default, no selectors/filters are applied — meaning all resources of the specified type are selected. kubectl get pods and kubectl get pods --field-selector "" are equivalent.
Example queries
Common field selector examples:
What is the key difference between field selectors and label selectors?
status.phase, spec.nodeName, metadata.namespace. Label selectors filter by user-defined label key/value pairs. They are complementary, not interchangeable.
Supported Fields & Operators
Universal fields (all resource types)
All resource types support metadata.name and metadata.namespace. Using an unsupported field selector produces an error.
Per-kind supported fields
| Kind | Additional Supported Fields |
|---|---|
| Pod | spec.nodeName, spec.restartPolicy, spec.schedulerName, spec.serviceAccountName, spec.hostNetwork, status.phase, status.podIP, status.podIPs, status.nominatedNodeName |
| Event | involvedObject.kind/namespace/name/uid/apiVersion/resourceVersion/fieldPath, reason, reportingComponent, source, type |
| Secret | type |
| Namespace | status.phase |
| ReplicaSet / ReplicationController | status.replicas |
| Job | status.successful |
| Node | spec.unschedulable |
| CertificateSigningRequest | spec.signerName |
Supported operators
Field selectors support =, == (same as =), and !=.
Set-based operators (in, notin, exists) are NOT supported for field selectors. Only equality and inequality operators work.
Custom resources
All custom resource types support metadata.name and metadata.namespace. Additionally, the spec.versions[*].selectableFields field of a CustomResourceDefinition declares which other fields may be used in field selectors.
Which of these field selector queries is INVALID?
in is a set-based operator — it is NOT supported for field selectors. Only =, ==, and != are valid. This is different from label selectors which do support in.
Chained & Multi-type Field Selectors
Chaining field selectors
Like label selectors, field selectors can be chained with a comma (AND logic). This selects all Pods where status.phase is not Running AND spec.restartPolicy is Always:
Multiple resource types
Field selectors can be used across multiple resource types in one command. This selects all StatefulSets and Services that are not in the default namespace:
Field selectors = filter by field values (not labels). Operators: =, ==, != only (no set-based). Universal fields: metadata.name, metadata.namespace. Can chain with comma (AND). Can target multiple resource types. Empty selector = no filter = all resources.
What does kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always return?
Recommended Labels
A common set of labels allows tools to work interoperably, describing objects in a manner that all tools can understand. These recommended labels describe applications in a way that can be queried.
All recommended labels share the app.kubernetes.io prefix. Labels without a prefix are private to users. The shared prefix ensures that shared labels do not interfere with custom user labels.
These are recommended, not required for any core tooling.
The 6 recommended label keys
| Key | Description | Example |
|---|---|---|
app.kubernetes.io/name | The name of the application | mysql |
app.kubernetes.io/instance | A unique name identifying the instance of an application | mysql-abcxyz |
app.kubernetes.io/version | The current version (SemVer 1.0, revision hash, etc.) | 5.7.21 |
app.kubernetes.io/component | The component within the architecture | database |
app.kubernetes.io/part-of | The name of a higher level application this one is part of | wordpress |
app.kubernetes.io/managed-by | The tool being used to manage the operation of an application | Helm |
name = the type of application (e.g. wordpress).
instance = the unique name of this specific deployment (e.g. wordpress-abcxyz).
This matters when the same application is installed multiple times — WordPress can be installed twice; each has the same name but a different instance.
StatefulSet example
Which label indicates that a MySQL StatefulSet is part of a larger WordPress application?
app.kubernetes.io/part-of indicates the higher-level application this component belongs to. The MySQL database is a part of the wordpress application. name would be "mysql" (the component's own name).
Recommended Labels — Examples
Simple stateless service (Deployment + Service)
Web application with database (WordPress + MySQL via Helm)
In a more complex app, each component carries labels for both itself and the broader application it belongs to:
Both WordPress and MySQL have different name, instance, and version, but they share part-of: wordpress. This lets tools discover all components of the WordPress application with a single label selector: app.kubernetes.io/part-of=wordpress.
WordPress is installed twice in the same cluster. What distinguishes the two installations?
name: wordpress (same application type). They differ by instance — each instance gets a unique name (often including a random suffix). This enables tools to distinguish and manage multiple instances of the same application.
Storage Versions
The Kubernetes API server stores objects in an etcd-compatible backing store. Each object is serialized using a particular version of that API type — this is called the storage version.
The Kubernetes API relies on automatic conversion. If you have a HorizontalPodAutoscaler with v1 and v2 APIs, you can interact with it using either version — Kubernetes converts each API call so clients don't see what version is actually serialized.
One storage version per resource at a time
The same API may have multiple storage versions, but a single object must only have one storage version at any time. The API Server knows all binary encodings and can convert between stored versions dynamically.
| Operation | Behavior |
|---|---|
| Reads | Convert stored data to the API representation — old storage versions can sit indefinitely as long as no updates occur |
| Writes | Convert the object to the current (new) storage version representation upon update/create |
The version of an object (e.g. v1alpha1 vs v1beta1) is separate from the storage version. A v1alpha1 and v1beta1 object for the same resource will be encoded the same in storage as long as the storage version hasn't changed between them.
An object was stored using an old storage version. It has not been updated. When you READ it via the API, what happens?
CRD Storage Versions & Encryption at Rest
Storage versions for custom resources
For Custom Resources (CRDs), a certain version must be explicitly set as the storage version. The schema defined by that version is used as the encoding in the storage layer.
One and only one version may be marked storage: true. Setting two versions as the storage version is considered invalid — it would mean two data schemas are valid ways to store the same object simultaneously. Only updating or creating will use the newly defined storage version; watching or getting an existing object will just convert from the old version.
Storage versions and encryption at rest
There are tools to encrypt at-rest storage, especially for cluster Secrets. This means the actual stored data is encrypted. The API Server must decrypt the data as it retrieves it, and must have the key for that storage version to decode the object properly.
The storage version is more than just the binary encoding — as long as what is stored can be converted into the API object, it can be used as a storage version. This matters for encryption because changing the storage version changes how the API server decodes the stored bytes.
In a CRD with two versions (v1beta1 and v1), v1beta1 is marked storage: true. What is the effect on the "time" field that only exists in the v1 schema?
time, then the time field cannot be stored — even if v1 supports it. This is explicitly noted in the docs: the v1 API object would never be able to store the time field since it's not part of the storage definition.
The Kubernetes API
The Kubernetes API lets you query and manipulate the state of objects in Kubernetes. The core of the control plane is the API server — users, cluster components, and external tools all communicate through it.
| Mechanism | Purpose |
|---|---|
| Discovery API | Brief summary: name, scope, URL, verbs. Not full schema. |
| OpenAPI Document | Full OpenAPI v2 and v3 schemas for all endpoints. |
Discovery API
Publishes a summary of all resources: name, scope, endpoint URL, supported verbs, alternative names, group/version/kind. It is a brief summary — not a full schema. For full schemas, use the OpenAPI document.
| Mode | Endpoints | Feature State |
|---|---|---|
| Aggregated | /api and /apis | Stable v1.30 — drastically reduces requests; requires special Accept header |
| Unaggregated | One endpoint per group/version | Default without Accept header; root endpoints act as discovery for downstream docs |
kubectl fetches and caches the API spec for command-line completion and cluster-awareness.
What does the Discovery API provide for each resource? (choose best answer)
OpenAPI & Protobuf Serialization
| OpenAPI v2 | OpenAPI v3 | |
|---|---|---|
| Endpoint | /openapi/v2 | /openapi/v3 + /openapi/v3/apis/<group>/<version>?hash=<h> |
| State | Stable | Stable since v1.27, enabled by default |
| Fidelity | Lossy — drops default, nullable, oneOf | Lossless — complete specification |
OpenAPI v3 URLs are immutable (hash-based) for client-side caching (Cache-Control: immutable, Expires 1 year). Obsolete URLs return a redirect.
OpenAPI schemas may not capture all validation. Use kubectl apply --dry-run=server for complete server-side validation including admission checks.
Protobuf serialization — alternative binary format, primarily for intra-cluster use. Persistence: Kubernetes stores serialized state in etcd. Kubernetes 1.36 publishes OpenAPI v2 and v3 — no plans for 3.1.
Why is OpenAPI v3 preferred over v2?
API Groups, Versioning & Changes
Kubernetes supports multiple API versions at different paths. Versioning is at the API level (not resource/field level). The API server converts transparently — all versions represent the same persisted data.
| Level | Compatibility guarantee | Notes |
|---|---|---|
| GA (v1) | Strong — Kubernetes commits to compatibility for official APIs | Also preserves beta-persisted data |
| Beta | Data preserved; must transition before deprecation ends | Best to migrate during deprecation period — both versions served simultaneously |
| Alpha | No guarantee — may break incompatibly | Check release notes; may need to delete all alpha objects before cluster upgrade |
Kubernetes aims NOT to break compatibility with existing clients. New resources and fields can be added frequently. Removing resources or fields requires following the API deprecation policy.
When MUST you migrate from a beta API?
API Extension
The Kubernetes API can be extended in two ways:
| Mechanism | Description |
|---|---|
| Custom Resources (CRDs) | Declaratively define new resource types — no additional code needed; API server serves them natively. |
| Aggregation Layer | Implement a custom extension API server; main API server proxies requests to it. |
CRDs = declarative, no code, simpler. Aggregation layer = custom code, more powerful/flexible.
What are the two mechanisms to extend the Kubernetes API?